package com.javacoo.junit.generator.codegen;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.Map;

import com.github.javaparser.ast.CompilationUnit;
import com.javacoo.junit.generator.api.plugin.TemplatePlugin;
import com.javacoo.junit.generator.config.ClassConfiguration;
import com.javacoo.junit.generator.config.Context;
import com.javacoo.junit.generator.internal.ObjectFactory;
import com.javacoo.junit.generator.internal.util.FileUtility;
import com.javacoo.junit.generator.internal.util.JavaparserUtility;
import com.javacoo.xkernel.spi.ExtensionLoader;

import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
import static com.javacoo.junit.generator.internal.util.StringUtility.stringHasValue;
import static com.javacoo.junit.generator.internal.util.messages.Messages.getString;

/**
 * 生成器默认实现类
 * <li>基于freemarker</li>
 * @author duanyong@jccfc.com
 * @date 2021/1/4 9:29
 */
public class JunitGenerator extends AbstractGeneratorPlugin {
    /**
     * 执行生成文件
     * <li></li>
     * @author duanyong@jccfc.com
     * @date 2021/1/5 9:58
     * @param context: 待执行的上下文
     * @return: void
     */
    @Override
    protected void execute(Context context){
        this.contextEnvment.getCallback().startTask(getString("Progress.0"));
        try{
            //freemarker配置
            freemarker.template.Configuration cfg = new freemarker.template.Configuration(freemarker.template.Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
            cfg.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER);

            //模板插件
            TemplatePlugin templatePlugin;
            //模板名称
            String templateName;
            //如果设置了模板处理类
            if(context.getTemplateConfiguration() != null && stringHasValue(context.getTemplateConfiguration().getTemplateHandlerName())){
                //获取指定处理类
                templatePlugin = ExtensionLoader.getExtensionLoader(TemplatePlugin.class).getExtension(context.getTemplateConfiguration().getTemplateHandlerName());
                if(templatePlugin == null){
                    warnings.add(getString("RuntimeError.22",context.getTemplateConfiguration().getTemplateHandlerName()));
                    return;
                }

                //模板名称
                templateName = stringHasValue(context.getTemplateConfiguration().getTemplateName()) ? context.getTemplateConfiguration().getTemplateName() : templatePlugin.getTemplateName();

                //如果配置了模板路径
                if(stringHasValue(context.getTemplateConfiguration().getTemplatePath())){
                    //设置freemarker模板路径
                    String templatePath = context.getTemplateConfiguration().getTemplatePath().startsWith("/") ? this.contextEnvment.getBaseDirectory().getAbsolutePath() + context.getTemplateConfiguration().getTemplatePath() : context.getTemplateConfiguration().getTemplatePath();
                    cfg.setDirectoryForTemplateLoading(new File(templatePath));
                }else{
                    cfg.setClassForTemplateLoading(this.getClass(), templatePlugin.getTemplatePath());
                }

            }else{
                templatePlugin = ExtensionLoader.getExtensionLoader(TemplatePlugin.class).getDefaultExtension();
                cfg.setClassForTemplateLoading(this.getClass(), templatePlugin.getTemplatePath());
                //模板名称
                templateName = templatePlugin.getTemplateName();
            }

            this.contextEnvment.getCallback().startTask(getString("Progress.1",templateName));
            //获取模板对象
            freemarker.template.Template template = cfg.getTemplate(templateName, "UTF-8");

            for(ClassConfiguration classConfiguration : context.getClassConfigurations()) {
                this.contextEnvment.getCallback().checkCancel();
                doExecute(templatePlugin,template,classConfiguration);
            }
        }catch(IOException e){
            e.printStackTrace();
            this.warnings.add(e.getMessage());
        } catch (InterruptedException e) {
            e.printStackTrace();
            this.warnings.add(e.getMessage());
        } catch (TemplateException e) {
            e.printStackTrace();
            this.warnings.add(e.getMessage());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            this.warnings.add(e.getMessage());
        }catch (Exception e) {
            e.printStackTrace();
            this.warnings.add(e.getMessage());
        }
    }
    /**
     * 执行生成
     * <li></li>
     * @author duanyong@jccfc.com
     * @date 2021/1/5 9:31
     * @param templatePlugin: 模板插件对象
     * @param template: 模板对象
     * @param classConfiguration: 类配置对象
     * @return: void
     */
    private void doExecute(TemplatePlugin templatePlugin, Template template, ClassConfiguration classConfiguration)
    throws IOException, TemplateException, ClassNotFoundException {
        //获取目标对象
        Class targetClass = ObjectFactory.internalClassForName(classConfiguration.getClassName());
        //获取模板数据
        Map<String, Object> data = templatePlugin.getTemplateData(targetClass);
        //获取待生成对象全路径名称
        String outFile = getOutFilePath(targetClass,this.outputDirectoryPath);
        this.contextEnvment.getCallback().startTask(getString("Progress.2",outFile));
        //待输出文件
        File file = new File(outFile);
        //如果是覆盖或者文件不存在，则直接生成
        if(this.contextEnvment.isOverwrite() || !file.exists()){
            //生成文件
            process(template,data, file);
        }else{
            if(this.contextEnvment.isBackup()){
                //备份上一次
                FileUtility.backup(outFile);
            }
            //获取已有文件
            CompilationUnit existingCompilationUnit = JavaparserUtility.getCompilationUnit(file).orElse(null);
            //生成新文件
            process(template,data, file);
            //获取新文件
            CompilationUnit newCompilationUnit = JavaparserUtility.getCompilationUnit(new File(outFile)).orElse(null);
            if(existingCompilationUnit != null && newCompilationUnit != null){
                //合并
                String fileString = JavaparserUtility.mergerFile(newCompilationUnit,existingCompilationUnit);
                //生成
                FileUtility.writeStringToFile(outFile, fileString);
            }
        }
    }

    /**
     * 组装模板数据,并生成文件
     * <li></li>
     * @author duanyong@jccfc.com
     * @date 2021/1/21 15:17
     * @param template: 模板引擎对象
     * @param data: 数据
     * @param file: 文件
     * @return: void
     */
    private void process(Template template,Map<String, Object> data,File file) throws IOException, TemplateException {
        //生成文件
        Writer out = new FileWriter(file);
        template.process(data, out);
    }
}
